package com.jt.www.admin.order_pc.controller;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.jt.www.admin.order_pc.service.ExportConfigService;
import com.jt.www.admin.order_pc.service.OfflineOrderService;
import com.jt.www.admin.user.service.UserService;
import com.jt.www.annotations.AvoidRepeatableCommit;
import com.jt.www.domain.bo.OfflineOrderBO;
import com.jt.www.domain.dto.OfflineOrderInputDTO;
import com.jt.www.domain.dto.OfflineOrderOutputDTO;
import com.jt.www.domain.dto.OfflineProductDTO;
import com.jt.www.domain.enums.common.ExportChannelTypeEnum;
import com.jt.www.domain.po.ExportConfigEntity;
import com.jt.www.domain.po.OfflineOrder;
import com.jt.www.domain.qo.OfflineOrderQO;
import com.jt.www.domain.qo.OfflinePolicyQO;
import com.jt.www.domain.qo.SavePolicyDetailFileQo;
import com.jt.www.domain.vo.OfflineOrderVo;
import com.jt.www.model.reps.GenericDataResponse;
import com.jt.www.model.reps.GenericListResponse;
import com.jt.www.util.RedisUtil;
import com.jt.www.util.excel.CsvExportUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 线下保单录入业务
 * Created by shaoyn on 2020/05/22.
 */
@Api(value = "保单录入", tags = {"OFFLINE-ORDER-API"}, description = "保单录入")
@RestController
@RequestMapping(value = "/offline/order")
public class OfflineOrderController {

    public static final Logger log = LoggerFactory.getLogger(OfflineOrderController.class);

    private static final String JTPF_USER_ID = "jtpf.userId";

    private static final String AUDIT_OFFLINE_ORDER = "AUDIT_OFFLINE_ORDER_";

    @Autowired
    private OfflineOrderService offlineOrderService;
    @Autowired
    private ExportConfigService exportConfigService;
    @Autowired
    private UserService userService;

    /**
     * 保单录入
     *
     * @return
     */
    @ApiOperation(value = "保单录入", notes = "保单录入", httpMethod = "POST")
    @PostMapping(value = "/saveOfflineOrder", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    @AvoidRepeatableCommit
    public ResponseEntity saveOfflineOrder(@RequestBody OfflineOrderInputDTO offlineOrderInputDTO) {
        //如果产品信息为空或 产品编码为空 返回报错信息
        if (null == offlineOrderInputDTO || StringUtils.isBlank(offlineOrderInputDTO.getPolicyFile())) {
            return GenericDataResponse.errorWithMsg("保单信息不能为空!");
        }
        if (StringUtils.isBlank(offlineOrderInputDTO.getBranchCode())) {
            return GenericDataResponse.errorWithMsg("业务归属不能为空!");
        }
        if (StringUtils.isBlank(offlineOrderInputDTO.getInsCompanyCode())) {
            return GenericDataResponse.errorWithMsg("出单公司不能为空!");
        }
        if (StringUtils.isBlank(offlineOrderInputDTO.getCityCode())) {
            return GenericDataResponse.errorWithMsg("地区不能为空!");
        }
        if (StringUtils.isBlank(offlineOrderInputDTO.getRiskDutyLimit())) {
            return GenericDataResponse.errorWithMsg("险种责任不能为空!");
        }
        if (StringUtils.isBlank(offlineOrderInputDTO.getProductCode())) {
            return GenericDataResponse.errorWithMsg("产品不能为空!");
        }
        String findCode = "saveOfflineOrder_" + System.currentTimeMillis();
        try {
            return offlineOrderService.saveOfflineOrder(findCode, offlineOrderInputDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return GenericDataResponse.errorWithMsg(e.getMessage());
        }
    }

    /**
     * 查询保单录入保单列表
     *
     * @return
     */
    @ApiOperation(value = "查询保单录入保单列表", notes = "查询保单录入保单列表", httpMethod = "POST")
    @PostMapping(value = "/queryOfflinePolicy", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity<GenericListResponse<OfflineOrderVo>> queryOfflinePolicy(@RequestBody OfflinePolicyQO offlinePolicyQO, HttpServletRequest request) {
        String findCode = "queryOfflinePolicy_" + System.currentTimeMillis();
        String userCode = request.getHeader(JTPF_USER_ID);
        String branchCodes = userService.getBranchCodes(findCode, userCode);
        offlinePolicyQO.setOperatorBranchCode(branchCodes);
        if (StringUtils.isBlank(userCode)) {
            log.info("{} 无用户信息!", findCode);
            return GenericListResponse.listNoCount(null);
        }
        return offlineOrderService.queryOfflinePolicy(offlinePolicyQO);
    }

    /**
     * 保单录入清单跨期校验
     *
     * @return
     */
    @ApiOperation(value = "保单录入清单跨期校验", notes = "保单录入清单跨期校验", httpMethod = "POST")
    @PostMapping(value = "/checkFileIntertemporal", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity checkFileIntertemporal(@RequestBody String policyFile)throws Exception {
        String findCode = "checkFileIntertemporal_" + System.currentTimeMillis();
        return offlineOrderService.checkFileIntertemporal(findCode,policyFile);
    }

    /**
     * 保单重新认领
     * @return
     */
    @ApiOperation(value = "保单重新认领功能", notes = "保单重新认领功能", httpMethod = "POST")
    @PostMapping(value = "/reclaim", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity reclaim(@RequestBody List<Map<String, String>> operparam) throws Exception{
        String findCode = "reclaim_"+System.currentTimeMillis();
        log.info("{}保单重新认领功能!", findCode);
        return offlineOrderService.reclaim(operparam);

    }

    /**
     * 查询保单录入订单列表
     *
     * @return
     */
    @ApiOperation(value = "查询保单录入订单列表", notes = "查询保单录入订单列表", httpMethod = "POST")
    @PostMapping(value = "/queryOfflineOrder", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity<GenericListResponse<OfflineOrder>> queryOfflineOrder(@RequestBody OfflineOrderQO offlineOrderQO, HttpServletRequest request) {
        String findCode = "queryOfflineOrder_" + System.currentTimeMillis();
        String userCode = request.getHeader(JTPF_USER_ID);
        String branchCodes = userService.getBranchCodes(findCode, userCode);
        offlineOrderQO.setOperatorBranchCode(branchCodes);
        if (StringUtils.isBlank(userCode)) {
            log.info("{} 无用户信息!", findCode);
            return GenericListResponse.listNoCount(null);
        }
        return offlineOrderService.queryOfflineOrder(offlineOrderQO);
    }

    /**
     * 查询保单录入详情
     *
     * @return
     */
    @ApiOperation(value = "查询保单录入详情", notes = "查询保单录入详情", httpMethod = "POST")
    @PostMapping(value = "/queryOfflineOrderDetails/{orderId}", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity<GenericDataResponse<OfflineOrderBO>> queryOfflineOrderDetails(@ApiParam(value = "线下录单定单ID", required = true) @PathVariable Long orderId) {
        return offlineOrderService.queryOfflineOrderDetails(orderId);
    }

    /**
     * 修改保单录入
     *
     * @return
     */
    @ApiOperation(value = "修改保单录入", notes = "修改保单录入", httpMethod = "POST")
    @PostMapping(value = "/updateOfflineOrder", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity updateOfflineOrder(@RequestBody OfflineOrderInputDTO offlineOrderInputDTO) {
        String findCode = "updateOfflineOrder_" + System.currentTimeMillis();
        if (null == offlineOrderInputDTO || null == offlineOrderInputDTO.getId()
                || StringUtils.isBlank(offlineOrderInputDTO.getPolicyFile())) {
            return GenericDataResponse.errorWithMsg("保单信息不能为空!");
        }
        try {
            return offlineOrderService.updateOfflineOrder(findCode, offlineOrderInputDTO);
        } catch (Exception e) {
            if (StringUtils.isBlank(e.getMessage())) {
                log.error("{},修改保单录入异常", findCode, e);
                return GenericDataResponse.errorWithMsg("修改保单录入异常, 请联系管理人员。");
            }
            return GenericDataResponse.errorWithMsg(e.getMessage());
        }
    }

    /**
     * 审核保单
     *
     * @return
     */
    @ApiOperation(value = "审核保单", notes = "审核保单", httpMethod = "POST")
    @PostMapping(value = "/auditOfflineOrder", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    @AvoidRepeatableCommit
    public ResponseEntity auditOfflineOrder(@RequestBody OfflineOrder offlineOrder) {
        if (null == offlineOrder || null == offlineOrder.getId()
                || StringUtils.isBlank(offlineOrder.getAuditStatus())) {
            return GenericDataResponse.errorWithMsg("保单信息/审核状态不能为空!");
        }
        String findCode = "auditOfflineOrder_" + System.currentTimeMillis();

        String redisKey = AUDIT_OFFLINE_ORDER + offlineOrder.getId();
        if (!RedisUtil.setOneHoursLock(redisKey)) {
            return GenericDataResponse.errorWithMsg("审核请求处理中，请稍等!");
        }
        log.info("{}保单审核任务开始!", findCode);
        try {
            return offlineOrderService.auditOfflineOrder(findCode, offlineOrder);
        } catch (Exception e) {
            return GenericDataResponse.errorWithMsg(e.getMessage());
        } finally {
            //删除缓存
            RedisUtil.delete(redisKey);
            log.info("{}保单审核任务结束!", findCode);
        }
    }


    /**
     * 通过保单号查询线下录入保单信息
     *
     * @return
     */
    @ApiOperation(value = "通过保单号查询线下录入保单信息", notes = "通过保单号查询线下录入保单信息", httpMethod = "POST")
    @PostMapping(value = "/queryByPolicyNo/{policyNo}", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity<GenericDataResponse<OfflineOrderVo>> queryByPolicyNo(@ApiParam(value = "线下录入保单号", required = true) @PathVariable String policyNo) {
        try {
            OfflineOrderVo offlineOrderVo = offlineOrderService.queryByPolicyNo(policyNo);
            return GenericDataResponse.okWithData(offlineOrderVo);
        } catch (Exception e) {
            return GenericDataResponse.errorWithMsg(e.getMessage(), OfflineOrderVo.class);
        }
    }

    /**
     * 推送定单下未成功推送的保单到投保中心
     *
     * @return
     */
    @ApiOperation(value = "推送定单下未成功推送的保单到投保中心", notes = "推送定单下未成功推送的保单到投保中心", httpMethod = "POST")
    @PostMapping(value = "/pushPolicyToIns/{orderId}", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity pushPolicyToIns(@ApiParam(value = "定单id", required = true) @PathVariable Long orderId) {
        if (null == orderId) {
            return GenericDataResponse.errorWithMsg("推送序列不能为空!");
        }
        String findCode = "PushErrorPolicyToIns_" + System.currentTimeMillis();
        //与审核同用一个key
        String redisKey = AUDIT_OFFLINE_ORDER + orderId;
        //if (!RedisUtil.setOneHoursLock(redisKey)) {
            //return GenericDataResponse.errorWithMsg("审核请求处理中，请稍等!");
        //}
        log.info("{}保单审核任务开始!", findCode);
        try {
            offlineOrderService.pushPolicyToIns(findCode, orderId);
            return GenericDataResponse.ok();
        } catch (Exception e) {
            return GenericDataResponse.errorWithMsg(e.getMessage());
        } finally {
            //删除缓存
            RedisUtil.delete(redisKey);
            log.info("{}保单审核任务结束!", findCode);
        }
    }

    /**
     * 检查保单号是否重复录入
     *
     * @return
     */
    @ApiOperation(value = "检查保单号是否重复录入", notes = "检查保单号是否重复录入", httpMethod = "POST")
    @PostMapping(value = "/checkPolicyNos", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity checkPolicyNos(String policyNos) {
        try {
            if (StringUtils.isBlank(policyNos)) {
                return GenericDataResponse.errorWithMsg("保单号不能为空!");
            }
            List<String> errorPolicyNos = offlineOrderService.checkPolicyNos(Arrays.asList(policyNos.split(",")));
            if (CollectionUtils.isEmpty(errorPolicyNos)) {
                return GenericDataResponse.ok();
            }
            return GenericDataResponse.errorWithMsg("保单号:" + String.join(",", errorPolicyNos) + "已经录入!");
        } catch (Exception e) {
            return GenericDataResponse.errorWithMsg(e.getMessage());
        }
    }

    @ApiOperation(value = "导出线下保单列表", notes = "统计结果并下载")
    @GetMapping(value = "/downList", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public void downList(OfflinePolicyQO offlinePolicyQO, HttpServletResponse response, HttpServletRequest request) {


        String findCode = "EDU_" + System.currentTimeMillis();
        String userCode = request.getHeader(JTPF_USER_ID);
        String branchCodes = userService.getBranchCodes(findCode, userCode);
        offlinePolicyQO.setOperatorBranchCode(branchCodes);

        OutputStream os = null;
        try {
            //查询导出配置
            ExportConfigEntity exportConfigEntity = exportConfigService.getExportConfig(ExportChannelTypeEnum.OFFLINE_ORDER.getCode());
            if (null == exportConfigEntity) {
                return;
            }
            String fileName = exportConfigEntity.getFileName();

            os = response.getOutputStream();
            CsvExportUtil.responseSetProperties(fileName, response);
            //模板位置
            String titles = exportConfigEntity.getTitles();
            CsvExportUtil.setTitles(titles, os);
            List<OfflineOrderVo> appList;
            int pn = 1;
            offlinePolicyQO.setPn(pn);
            offlinePolicyQO.setPs(CsvExportUtil.MAX_PAGE_SIZE);
            String[] keyArr = exportConfigEntity.getKeyArr().split(",");

            //分批查询并生成数据插入到导出文件中
            while (CollectionUtils.isNotEmpty(appList = offlineOrderService.queryOfflinePolicy(offlinePolicyQO).getBody().getList())) {
                List list = Lists.transform(appList, (Function<OfflineOrderVo, Object>) offlineOrderVo -> new OfflineOrderOutputDTO(offlineOrderVo));
                CsvExportUtil.doExport(list, keyArr, os);
                offlinePolicyQO.setPn(++pn);
                if (offlinePolicyQO.getPs() > appList.size()) {
                    break;
                }
            }
        } catch (Exception e) {
            log.error("{}导出发生错误:", findCode, e);
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                }
            }
        }
    }


    /**
     * 删除订单
     *
     * @return
     */
    @ApiOperation(value = "删除订单", notes = "删除订单", httpMethod = "GET")
    @GetMapping(value = "/deleteOrder/{orderId}", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity deleteOrder(@ApiParam(value = "线下录单定单ID", required = true) @PathVariable Long orderId) {
        if (null == orderId) {
            return GenericDataResponse.errorWithMsg("保单号不能为空!");
        }
        return offlineOrderService.deleteOrder(orderId);
    }


    /**
     * 查询关联的人员清单
     *
     * @return
     */
    @ApiOperation(value = "查询关联的人员清单", notes = "查询关联的人员清单", httpMethod = "GET")
    @GetMapping(value = "/selectPolicyDetailFile/{policyNo}", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity selectPolicyDetailFile(@ApiParam(value = "保单号", required = true) @PathVariable String policyNo, HttpServletResponse response) {
        try {
            return offlineOrderService.selectPolicyDetailFile(policyNo);
        } catch (Exception e) {
            return GenericDataResponse.errorWithMsg(e.getMessage());
        }
    }


    /**
     * 关联人员清单
     *
     * @return
     */
    @ApiOperation(value = "关联人员清单", notes = "关联人员清单", httpMethod = "POST")
    @PostMapping(value = "/savePolicyDetailFile", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    @AvoidRepeatableCommit
    public ResponseEntity savePolicyDetailFile(@RequestBody SavePolicyDetailFileQo savePolicyDetailFileQo) {
        String findCode = "savePolicyDetailFile_" + System.currentTimeMillis();
        try {
            return offlineOrderService.savePolicyDetailFile(findCode, savePolicyDetailFileQo);
        } catch (Exception e) {
            return GenericDataResponse.errorWithMsg(e.getMessage());
        }
    }

    /**
     * 通过用户查询线下录入的产品列表
     *
     * @return
     */
    @ApiOperation(value = "通过用户查询线下录入的产品列表", notes = "通过用户查询线下录入的产品列表", httpMethod = "GET")
    @GetMapping(value = "/offlineProductList", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity<GenericListResponse<OfflineProductDTO>> offlineProductList(@RequestHeader("jtpf.userId") @ApiParam(value = "token解析的userId", required = true) String userCode) {
        String findCode = "OfflineProductList_" + System.currentTimeMillis();
        log.info("{} 通过用户查询线下录入的产品列表, userCode:{}", findCode, userCode);
        try {
            if (StringUtils.isNotBlank(userCode)) {
                return offlineOrderService.offlineProductList(findCode, userCode);
            }
        } catch (Exception e) {
            log.error("{} 异常:{} ", findCode, e.getMessage(), e);
        }
        return GenericListResponse.listNoCount(Lists.newArrayList());
    }


}
